package com.zlp.utils.hashcode;

import com.google.common.collect.Lists;
import org.apache.commons.lang3.time.DateFormatUtils;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;

/**
 * @title: Demo
 * @projectName: aliyunOssExample
 * @description: jdk1.8新特性：日期与时间应用
 * @author: Lu Zhaochun
 * @date: 2020/6/9 14:36
 */
public class DateUtil {

    private static final String YYYYMMDDHHMMSS = "yyyy-MM-dd HH:mm:ss";
    private static final String YYYYMMDD = "yyyy-MM-dd";
    private static final String YYYYMM = "yyyy-MM";

    /**
     * 将日期转为字符串 yyyy-mm-dd HH:mm:ss
     *
     * @param date
     * @return
     */
    public static String getYYYYMMDDHHMMSS(Date date) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(YYYYMMDDHHMMSS);
        LocalDateTime localDateTime = dateToDateTime(date);

        return formatter.format(localDateTime);
    }

    /**
     * 得到当前日期 yyyy-MM-dd
     * @return
     */
    public static String getNowDate(){
        return LocalDate.now().toString();
    }

    /**
     * 将字符串转为日期
     *
     * @param date
     * @return
     */
    public static Date getDate(String date) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(YYYYMMDDHHMMSS);
        LocalDateTime localDateTime = LocalDateTime.parse(date, dateTimeFormatter);
        return dateTimeToDate(localDateTime);
    }

    /**
     * 将字符串转为日期
     *
     * @param date
     * @return
     */
    public static Date getDateDay(String date) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(YYYYMMDD);
        LocalDate localDateTime = LocalDate.parse(date, dateTimeFormatter);
        return localToDate(localDateTime);
    }

    /**
     * 将字符串转为日期
     *
     * @param date
     * @return
     */
    public static Date getDateMouth(String date) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(YYYYMM);
        LocalDate localDateTime = LocalDate.parse(date, dateTimeFormatter);
        return localToDate(localDateTime);
    }

    /**
     * 将字符串转为日期
     *
     * @param date
     * @param pattern
     * @return
     */
    public static Date getDate(String date, String pattern) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
        LocalDateTime localDateTime = LocalDateTime.parse(date, dateTimeFormatter);
        return dateTimeToDate(localDateTime);
    }

    /**
     * LocalDateTime 和DateTime 互转
     *
     * @param date
     * @return
     */
    public static LocalDateTime dateToDateTime(Date date) {
        Instant instant = date.toInstant();
        return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
    }

    public static Date dateTimeToDate(LocalDateTime localDateTime) {
        Date date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
        return date;
    }

    /**
     * date 转LocalDate
     *
     * @param date
     * @return
     */
    public static LocalDate dateToLocalDate(Date date) {
        Instant instant = date.toInstant();
        LocalDate localDate = instant.atZone(ZoneId.systemDefault()).toLocalDate();
        return localDate;
    }

    /**
     * LocalDate 转date
     *
     * @param localDate
     * @return
     */
    public static Date localToDate(LocalDate localDate) {
        Date date = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
        return date;
    }

    /**
     * date 转DateTime
     *
     * @param date
     * @return
     */
    public static LocalTime dateToLocalTime(Date date) {
        Instant instant = date.toInstant();
        LocalTime localTime = instant.atZone(ZoneId.systemDefault()).toLocalTime();
        return localTime;
    }

    /**
     * localTime 转date
     *
     * @param localTime
     * @return
     */
    public static Date localToDate(LocalTime localTime) {
        LocalDate localDate = LocalDate.now();
        LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);
        ZoneId zone = ZoneId.systemDefault();
        Instant instant = localDateTime.atZone(zone).toInstant();
        Date date = Date.from(instant);
        return date;
    }

    /**
     * 将日期转为字符串 yyyy-mm-dd
     *
     * @param date
     * @return
     */
    public static String getYYYYMMDD(Date date) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(YYYYMMDD);
        LocalDateTime localDateTime = dateToDateTime(date);
        return formatter.format(localDateTime);
    }

    /**
     * 将日期转为字符串 yyyy-mm-dd
     *
     * @param date
     * @return
     */
    public static String getYYYYMM(Date date) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(YYYYMM);
        LocalDateTime localDateTime = dateToDateTime(date);
        return formatter.format(localDateTime);
    }

    /**
     * 获取当前时间之后的某一天的最小时间
     *
     * @param date
     * @return
     */
    public static Date afterXDateTimeMIN(Date date, int after) {
        LocalDateTime localDateTime = dateToDateTime(date);
        localDateTime = localDateTime.plusDays(after);
        localDateTime = localDateTime.with(LocalTime.MIN);
        return dateTimeToDate(localDateTime);
    }

    /**
     * 获取当前时间之后的某一天的最大时间
     *
     * @param date
     * @param after
     * @return
     */
    public static Date afterXDateTimeMAX(Date date, int after) {
        LocalDateTime localDateTime = dateToDateTime(date);
        localDateTime = localDateTime.plusDays(after);
        localDateTime = localDateTime.with(LocalTime.MAX);
        return dateTimeToDate(localDateTime);
    }

    /**
     * 获取当前时间之前的某一天的最小时间
     *
     * @param date
     * @param before
     * @return
     */
    public static Date beforeXDateTimeMIN(Date date, int before) {
        LocalDateTime localDateTime = dateToDateTime(date);
        localDateTime = localDateTime.minusDays(before);
        localDateTime = localDateTime.with(LocalTime.MIN);
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 获取当前时间之前的某一天的最大时间
     *
     * @param date
     * @param before
     * @return
     */
    public static Date beforeXDateTimeMAX(Date date, int before) {
        LocalDateTime localDateTime = dateToDateTime(date);
        localDateTime = localDateTime.minusDays(before);
        localDateTime = localDateTime.with(LocalTime.MAX);
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 获取本月的第一天 00:00:00
     *
     * @return
     */
    public static Date currentFirstDayOfMonth() {
        LocalDateTime localDateTime = LocalDateTime.now();
        localDateTime = localDateTime.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN);
        return dateTimeToDate(localDateTime);
    }

    /**
     * 获取传入时间月份的最后一天
     *
     * @param date
     * @return
     */
    public static Date currentXDayOfMonth(Date date) {
        LocalDateTime localDateTime = dateToDateTime(date);
        localDateTime = localDateTime.with(TemporalAdjusters.lastDayOfMonth()).with(LocalTime.MAX);
        return dateTimeToDate(localDateTime);
    }

    /**
     * 所选date的月份的第一天
     *
     * @param date
     * @return
     */
    public static Date beforeXFirstDayOfMonth(Date date) {
        LocalDateTime localDateTime = dateToDateTime(date);
        localDateTime = localDateTime.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN);
        return dateTimeToDate(localDateTime);
    }

    /**
     * 获取前几个月的1号0点 00:00:00
     *
     * @param month
     * @return
     */
    public static Date preXDayOfMonthMIN(int month) {
        LocalDateTime localDateTime = LocalDateTime.now();
        localDateTime = localDateTime.minusMonths(month);
        localDateTime = localDateTime.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN);
        return dateTimeToDate(localDateTime);
    }

    /**
     * 获取前几个月的1号0点 00:00:00
     *
     * @param date
     * @param month
     * @return
     */
    public static Date preXDayOfMonthMIN(Date date, int month) {
        LocalDateTime localDateTime = dateToDateTime(date);
        localDateTime = localDateTime.minusMonths(month);
        localDateTime = localDateTime.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN);
        return dateTimeToDate(localDateTime);
    }

    /**
     * 传入时间的的前几个月的时间
     *
     * @param date
     * @param month
     * @return
     */
    public static Date preXDayOfMonth(Date date, int month) {
        LocalDateTime localDateTime = dateToDateTime(date);
        localDateTime = localDateTime.minusMonths(month);
        return dateTimeToDate(localDateTime);
    }

    /**
     * 传入时间的的前几个月的时间
     *
     * @param date
     * @param month
     * @return
     */
    public static Date afterXDayOfMonth(Date date, int month) {
        LocalDateTime localDateTime = dateToDateTime(date);
        localDateTime = localDateTime.plusMonths(month);
        return dateTimeToDate(localDateTime);
    }

    /**
     * 获取前几个月的最后一天23：59：59
     *
     * @param month
     * @return
     */
    public static Date preXDayOfMonthMAX(int month) {
        LocalDateTime localDateTime = LocalDateTime.now();
        localDateTime = localDateTime.minusMonths(month);
        localDateTime = localDateTime.with(TemporalAdjusters.lastDayOfMonth()).with(LocalTime.MAX);
        return dateTimeToDate(localDateTime);
    }

    /**
     * 获取某个时间几个月的最后一天23：59：59
     *
     * @param date
     * @param month
     * @return
     */
    public static Date preXDayOfMonthMAX(Date date, int month) {
        LocalDateTime localDateTime = dateToDateTime(date);
        localDateTime = localDateTime.minusMonths(month);
        localDateTime = localDateTime.with(TemporalAdjusters.lastDayOfMonth()).with(LocalTime.MAX);
        return dateTimeToDate(localDateTime);
    }

    /**
     * 两个日期相差多少个月
     *
     * @param date1
     * @param date2
     * @return
     */
    public static Long getUntilMonth(Date date1, Date date2) {
        LocalDate localDate1 = dateToLocalDate(date1);
        LocalDate localDate2 = dateToLocalDate(date2);
        return ChronoUnit.MONTHS.between(localDate1, localDate2);
    }

    /**
     * 两个日期相差多少天
     *
     * @param date1
     * @param date2
     * @return
     */
    public static Long getUntilDay(Date date1, Date date2) {
        LocalDate localDate1 = dateToLocalDate(date1);
        LocalDate localDate2 = dateToLocalDate(date2);
        return ChronoUnit.DAYS.between(localDate1, localDate2);
    }

    /**
     * 两个日期相差多少小时
     *
     * @param date1
     * @param date2
     * @return
     */
    public static Long getUntilHours(Date date1, Date date2) {
        LocalDateTime localDate1 = dateToDateTime(date1);
        LocalDateTime localDate2 = dateToDateTime(date2);
        Long senonds = Duration.between(localDate1, localDate2).get(ChronoUnit.SECONDS);
        return senonds / 3600;
    }

    /**
     * 两个日期相差多少小时 double 约等于
     *
     * @param date1
     * @param date2
     * @return
     */
    public static double getUntilHoursByDouble(Date date1, Date date2) {
        LocalDateTime localDate1 = dateToDateTime(date1);
        LocalDateTime localDate2 = dateToDateTime(date2);
        Long seconds = Duration.between(localDate1, localDate2).get(ChronoUnit.SECONDS);
        BigDecimal secondss = BigDecimal.valueOf(seconds);
        BigDecimal hours = secondss.divide(BigDecimal.valueOf(3600), 2, BigDecimal.ROUND_HALF_UP);
        return hours.doubleValue();
    }

    /**
     * 两个日期相差多少秒
     *
     * @param date1
     * @param date2
     * @return
     */
    public static Long getUntilSecond(Date date1, Date date2) {
        LocalDateTime localDate1 = dateToDateTime(date1);
        LocalDateTime localDate2 = dateToDateTime(date2);
        return Duration.between(localDate1, localDate2).get(ChronoUnit.SECONDS);
    }

    /**
     * 当前时间23：59：59
     *
     * @param date
     * @return
     */
    public static Date currentMax(Date date) {
        LocalDateTime localDateTime = dateToDateTime(date);
        localDateTime = localDateTime.with(LocalTime.MAX);
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 当前时间00:00:00
     *
     * @param date
     * @return
     */
    public static Date currentMin(Date date) {
        LocalDateTime localDateTime = dateToDateTime(date);
        localDateTime = localDateTime.with(LocalTime.MIN);
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    public static String getNowString() {
        return DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss", TimeZone.getTimeZone("GMT+8"));
    }

    public static boolean isInToday(Date date) {
        return date.getTime() >= todayStart().getTime() && date.getTime() <= todayEnd().getTime();
    }

    public static String dateConvertGMT8Str(Date date) {
        return DateFormatUtils.format(date, "yyyy-MM-dd HH:mm", TimeZone.getTimeZone("GMT+8"));
    }

    public static Date todayStart() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);

        return calendar.getTime();
    }

    public static Date todayEnd() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);

        return calendar.getTime();
    }

    public static String dateToStamp(String s) throws ParseException {
        String res;
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = simpleDateFormat.parse(s);
        long ts = date.getTime();
        res = String.valueOf(ts);
        return res;
    }

    public static String stampToDate(Long expiredAt) {
        String res;
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        long lt = new Long(expiredAt);
        Date date = new Date(lt);
        res = simpleDateFormat.format(date);
        return res;
    }

    public static String addDateMinut(String day, int min) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = null;
        try {
            date = format.parse(day);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        if (date == null) {
            return "";
        }

        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MINUTE, min);// 24小时制
        date = cal.getTime();

        return format.format(date);

    }

    /**
     * 为文件重新命名，命名规则为当前系统时间毫秒数
     *
     * @return string
     */
    public static String getFileNameNew() {
        SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMddHHmmss");
        return fmt.format(new Date());
    }

    /**
     * 以当前日期为名，创建新文件夹
     *
     * @return
     */
    public static String createNewDir() {
        SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMdd");
        return fmt.format(new Date());
    }

    public static int timeDiffOfDay(String start, String end) throws ParseException {
        SimpleDateFormat simpleFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        String fromDate = simpleFormat.format(start);
        String toDate = simpleFormat.format(end);
        long from = simpleFormat.parse(fromDate).getTime();
        long to = simpleFormat.parse(toDate).getTime();
        return (int) ((to - from) / (1000 * 60 * 60 * 24));
    }

    public static Long timeDiffOfMin(String sdate, String edate) throws ParseException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        Date start = simpleDateFormat.parse(sdate);
        Date end = simpleDateFormat.parse(edate);
        long between = (end.getTime() - start.getTime()) / 1000;
        long min = between / 60;
        return min;
    }

    /**
     * 方法描述：方法描述：获取节假日 访问接口，根据返回值判断当前日期是否为工做日，
     * 返回结果：检查具体日期是否为节假日，工做日对应结果为 0, 休息日对应结果为 1, 节假日对应的结果为 2；
     *
     * @author zc
     */
    public static String getHoliday(String time) {
        String dc = "http://tool.bitefu.net/jiari/?d=";
        String httpUrl = new StringBuffer().append(dc).append(time).toString();
        BufferedReader reader = null;
        String result = null;
        StringBuffer sbf = new StringBuffer();
        try {
            URL url = new URL(httpUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.connect();
            InputStream is = connection.getInputStream();
            reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
            String strRead = null;
            while ((strRead = reader.readLine()) != null) {
                sbf.append(strRead);
            }
            reader.close();
            result = sbf.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public static String getHolidayNext(Date time) {
        Calendar c = Calendar.getInstance();
        c.setTime(time);
        SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
        // 日期转化
        String twoDaysLater = df.format(time);
        String result = DateUtil.getHoliday(twoDaysLater);
        String lastDay = "";
        //警告，这种已知的字符串比较一定要加.trim()去空格
        while (!result.trim().equals("0")) {
            //如果目标日期是节假日则顺时开始下一天的判断
            c.add(Calendar.DATE, 1);
            lastDay = df.format(c.getTime());
            result = DateUtil.getHoliday(lastDay);
            if (result.trim().equals("0")) {
                //获取的日期不是节假日开始跳出循环
                return lastDay;
            }
        }
        return twoDaysLater;
    }

    //指定日期上加上指点天数
    public static Date addDate(Date date, long day) {
        // 得到指定日期的毫秒数
        long time = date.getTime();
        // 要加上的天数转换成毫秒数
        day = day * 24 * 60 * 60 * 1000;
        // 相加得到新的毫秒数
        time += day;
        // 将毫秒数转换成日期
        return new Date(time);
    }

    //指定日期上加上指点天数
    public static Date addDateFloat(Date date, float day) {
        // 得到指定日期的毫秒数
        long time = date.getTime();
        // 要加上的天数转换成毫秒数
        day = day * 24 * 60 * 60 * 1000;
        // 相加得到新的毫秒数
        time += day;
        // 将毫秒数转换成日期
        return new Date(time);
    }

    //嘉士伯日期格式
    public static String getCarDate(String date) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date parse = null;
        try {
            parse = simpleDateFormat.parse(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        SimpleDateFormat dateFormat = new SimpleDateFormat("MM-dd-YY");
        String format = dateFormat.format(parse);
        return format;
    }

    /**
     * 指定字符(yyyy-MM-dd HH:mm:ss)转换成时间戳
     *
     * @param dateStr
     * @return
     */
    public static Long getLongTimeByStringDefault(String dateStr) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(YYYYMMDDHHMMSS);
        try {
            Date date = simpleDateFormat.parse(dateStr);
            long ts = date.getTime();
            return ts;
        } catch (Exception e) {
            return 0L;
        }
    }

    /**
     * 获取前多少个月时间
     *
     * @return
     * @param: month
     */
    public static String getPreviousDateByMonth(int month) {
        Date dNow = new Date();   //当前时间
        Date dBefore = new Date();
        Calendar calendar = Calendar.getInstance(); //得到日历
        calendar.setTime(dNow);//把当前时间赋给日历
        calendar.add(Calendar.MONTH, -month);  //设置为前n月
        dBefore = calendar.getTime();   //得到前---月的时间
        SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDDHHMMSS); //设置时间格式
        String defaultStartDate = sdf.format(dBefore);    //格式化前n月的时间
        return defaultStartDate;
    }

    /**
     * 获取当前一周时间
     * @return
     * @throws Exception
     */
    public static List<String> getNowDatWeek() throws Exception{
        final ArrayList<String> list = Lists.newArrayList(
                "星期一", "星期二", "星期三", "星期四",
                "星期五", "星期六", "星期日"
        );
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Calendar calendar = Calendar.getInstance();
        //现在时间
        String  recipeTime = simpleDateFormat.format(new Date());
        calendar.setTime(simpleDateFormat.parse(recipeTime));
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        int week = calendar.get(Calendar.DAY_OF_WEEK);
        if (1 == week) {
            calendar.add(Calendar.DAY_OF_MONTH, -1);
        }
        int getDayFirst =calendar.get(Calendar.DAY_OF_WEEK);
        calendar.add(Calendar.DATE, calendar.getFirstDayOfWeek() - getDayFirst);
        //本周星期一
        String beginDate = simpleDateFormat.format(calendar.getTime());
        //本周星期日
        calendar.add(Calendar.DATE, 6);
        String endDate = simpleDateFormat.format(calendar.getTime());
        ArrayList<String> dateStr = Lists.newArrayList();
        for (int i = 0; i < list.size(); i++) {
            calendar.setFirstDayOfWeek(Calendar.MONDAY);
            calendar.set(Calendar.DAY_OF_WEEK,Calendar.MONDAY);
            long time = calendar.getTimeInMillis() + 24*60*60*1000*i;
            String sunday = simpleDateFormat.format(time);
            dateStr.add(sunday);
        }
        return dateStr;
    }

    /**
     * 获取当前日期最后时间
     * @param date
     * @return
     */
    public static String getEndTime(Date date){
        return DateFormatUtils.format(date, "yyyy-MM-dd 23:59:59");
    }


}
